From 046a6c59e96d64a8e9d47031a5c0a863c57a8a7a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 19 May 2015 23:07:15 -0700 Subject: [PATCH] Reduce calls to fs::metadata in list_git_files When walking over entries in the index of a git repository the file type can be known without a syscall (in the form of a libc constant), but walking over untracked files still requires a syscall to determine if it's a directory. --- src/cargo/sources/path.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/cargo/sources/path.rs b/src/cargo/sources/path.rs index 16681226e..877d69e31 100644 --- a/src/cargo/sources/path.rs +++ b/src/cargo/sources/path.rs @@ -4,8 +4,9 @@ use std::fs; use std::io::prelude::*; use std::path::{Path, PathBuf}; -use glob::Pattern; use git2; +use glob::Pattern; +use libc; use core::{Package, PackageId, Summary, SourceId, Source, Dependency, Registry}; use ops; @@ -146,15 +147,19 @@ impl<'cfg> PathSource<'cfg> { // Here we're also careful to look at both tracked an untracked files as // the untracked files are often part of a build and may become relevant // as part of a future commit. - let index_files = index.iter().map(|entry| join(&root, &entry.path)); + let index_files = index.iter().map(|entry| { + let is_dir = entry.mode & (libc::S_IFMT as u32) == + (libc::S_IFDIR as u32); + (join(&root, &entry.path), Some(is_dir)) + }); let mut opts = git2::StatusOptions::new(); opts.include_untracked(true); let statuses = try!(repo.statuses(Some(&mut opts))); let untracked = statuses.iter().map(|entry| { - join(&root, entry.path_bytes()) + (join(&root, entry.path_bytes()), None) }); - 'outer: for file_path in index_files.chain(untracked) { + 'outer: for (file_path, is_dir) in index_files.chain(untracked) { let file_path = try!(file_path); // Filter out files outside this package. @@ -176,9 +181,10 @@ impl<'cfg> PathSource<'cfg> { } } - // TODO: the `entry` has a mode we should be able to look at instead - // of just calling stat() again - if fs::metadata(&file_path).map(|m| m.is_dir()).unwrap_or(false) { + let is_dir = is_dir.or_else(|| { + fs::metadata(&file_path).ok().map(|m| m.is_dir()) + }).unwrap_or(false); + if is_dir { warn!(" found submodule {}", file_path.display()); let rel = util::without_prefix(&file_path, &root).unwrap(); let rel = try!(rel.to_str().chain_error(|| { -- 2.30.2